use rand::Rng;
use std::cmp;

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Color {
    NONE,
    RED,
    ORANGE,
    YELLOW,
    GREEN,
    CYAN,
    BLUE,
    PURPLE,
    WHITE,
}

// https://github.com/fidian/ansi
impl Color {
    pub fn to_str(&self) -> &'static str {
        match self {
            Color::RED => "9",
            Color::ORANGE => "208",
            Color::YELLOW => "11",
            Color::GREEN => "10",
            Color::CYAN => "14",
            Color::BLUE => "4",
            Color::PURPLE => "13",
            Color::WHITE => "15",
            Color::NONE => "15",
        }
    }
}

// https://harddrop.com/
#[derive(Clone)]
pub enum TerominoType {
    I, // xxxx
    // oooo
    O, // oxxo
    // oxxo
    T, // oxxx
    // ooxo
    S, // ooxx
    // oxxo
    Z, // xxoo
    // oxxo
    J, // xxxo
    // ooxo
    L, // oxxx
}

impl TerominoType {
    pub fn rand(r: u32) -> Self {
        match r % 7 {
            0 => TerominoType::O,
            1 => TerominoType::I,
            2 => TerominoType::Z,
            5 => TerominoType::S,
            3 => TerominoType::T,
            4 => TerominoType::J,
            6 => TerominoType::L,
            _ => TerominoType::L,
        }
    }
}

#[derive(Clone)]
pub struct Teromino {
    pub shape: Vec<Vec<i32>>,
    pub teromino_type: TerominoType,
    pub color: Color,
    pub x: i32,
    pub y: i32,
}

impl Teromino {
    pub fn new(ttype: TerominoType, pos_x: i32, pos_y: i32) -> Self {
        match ttype {
            TerominoType::I => Teromino {
                shape: vec![
                    vec![0, 0, 0, 0, 0],
                    vec![0, 0, 0, 0, 0],
                    vec![0, 1, 1, 1, 1],
                    vec![0, 0, 0, 0, 0],
                    vec![0, 0, 0, 0, 0],
                ],
                teromino_type: ttype,
                color: Color::CYAN,
                x: pos_x,
                y: pos_y - 3,
            },
            TerominoType::O => Teromino {
                shape: vec![vec![0, 1, 1], vec![0, 1, 1], vec![0, 0, 0]],
                teromino_type: ttype,
                color: Color::YELLOW,
                x: pos_x,
                y: pos_y - 2,
            },
            TerominoType::J => Teromino {
                shape: vec![vec![1, 0, 0], vec![1, 1, 1], vec![0, 0, 0]],
                teromino_type: ttype,
                color: Color::BLUE,
                x: pos_x,
                y: pos_y - 2,
            },
            TerominoType::L => Teromino {
                shape: vec![vec![0, 0, 1], vec![1, 1, 1], vec![0, 0, 0]],
                teromino_type: ttype,
                color: Color::ORANGE,
                x: pos_x,
                y: pos_y - 2,
            },
            TerominoType::S => Teromino {
                shape: vec![vec![0, 1, 1], vec![1, 1, 0], vec![0, 0, 0]],
                teromino_type: ttype,
                color: Color::GREEN,
                x: pos_x,
                y: pos_y - 2,
            },
            TerominoType::Z => Teromino {
                shape: vec![vec![1, 1, 0], vec![0, 1, 1], vec![0, 0, 0]],
                teromino_type: ttype,
                color: Color::RED,
                x: pos_x,
                y: pos_y - 2,
            },
            TerominoType::T => Teromino {
                shape: vec![vec![0, 1, 0], vec![1, 1, 1], vec![0, 0, 0]],
                teromino_type: ttype,
                color: Color::PURPLE,
                x: pos_x,
                y: pos_y - 2,
            },
        }
    }

    pub fn new_rand(pos_x: i32, pos_y: i32) -> Self {
        let mut rng = rand::thread_rng();
        let r = rng.gen();
        let mut t = Teromino::new(TerominoType::rand(r), pos_x, pos_y);
        for _ in 0..r%4 {
            t.rotate();
        }
        return t;
    }

    pub fn rotate(&mut self) {
        // t[i][j] -> t'[j][3 - i - 1]
        let n = self.shape.len();
        let mut new_shape = vec![vec![0; n]; n];
        for i in 0..n {
            for j in 0..n {
                new_shape[j][n - i - 1] = self.shape[i][j];
            }
        }
        self.shape = new_shape;
    }

    // 底部距离
    pub fn bound_bottom(&self) -> i32 {
        let mut bound_bottom: i32 = 0;
        for i in 0..self.shape.len() {
            let row = self.shape.len() - i - 1;
            for col in 0..self.shape[row].len() {
                if self.shape[row][col] > 0 {
                    bound_bottom = row as i32;
                    return bound_bottom;
                }
            }
        }
        return bound_bottom;
    }

    // 左侧距离
    pub fn bound_left(&self) -> i32 {
        let mut left = 0;
        for col in 0..self.shape[0].len() {
            for row in 0..self.shape.len() {
                if 1 == self.shape[row][col] {
                    left = col;
                    return self.y + left as i32;
                }
            }
        }
        self.y + left as i32
    }

    pub fn bound_right(&self) -> i32 {
        let mut bound_right = 0;
        for row in 0..self.shape[0].len() {
            for col in 0..self.shape[row].len() {
                if 1 == self.shape[row][col] {
                    bound_right = cmp::max(bound_right, col);
                }
            }
        }
        bound_right as i32
    }

    pub fn debug(&self) {
        for i in 0..self.shape.len() {
            println!("");
            for j in 0..self.shape[i].len() {
                print!("{}", self.shape[i][j]);
            }
        }
    }
}
